package com.meng.baselibrary;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2017/5/4.
 */

public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler{
    private static ExceptionCrashHandler instance;
    private static final String TAG = "ExceptionCrashHandler";
    private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
    private ExceptionCrashHandler(){

    }
    public static ExceptionCrashHandler getInstance(){
        if(instance == null){
            synchronized (ExceptionCrashHandler.class){
                if(instance == null){
                    instance = new ExceptionCrashHandler();
                }
            }
        }
        return instance;
    }
    //用来获取一些应用版本等信息
    private Context mContext;
    public void init(Context context){
        this.mContext = context;
        //设置全局异常类为本类
        mDefaultExceptionHandler = Thread.currentThread().getDefaultUncaughtExceptionHandler();
        Thread.currentThread().setUncaughtExceptionHandler(this);
    }
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Log.d(TAG, "报异常了");
        //写入本地文件
        String crashFileName = saveInfoToSD(e);
        Log.e(TAG, crashFileName);
        cacheCrashFile(crashFileName);
        //让系统默认处理异常
        mDefaultExceptionHandler.uncaughtException(t,e);
    }

    /**
     * 缓存崩溃日志文件
     * @param crashFileName
     */
    private void cacheCrashFile(String crashFileName) {
        SharedPreferences sp = mContext.getSharedPreferences("crash",Context.MODE_PRIVATE);
        sp.edit().putString("CRASH_FILE_NAME",crashFileName).commit();
    }

    /**
     * 获取崩溃文件
     * @return
     */
    public File getCrashFile(){
        String crashFileName = mContext.getSharedPreferences("crash",Context.MODE_PRIVATE)
                .getString("CRASH_FILE_NAME","");
        return new File(crashFileName);
    }
    private String saveInfoToSD(Throwable e) {
        String fileName = null;
        StringBuffer sb = new StringBuffer();
        for(Map.Entry<String,String> entry:obtainSimpleInfo(mContext).entrySet()){
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append(" = ").append(value).append("\n");
        }
        //拼接崩溃的详细信息
        sb.append(obtainExceptionInfo(e));
        //保存文件
        if(Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)){
            File dir = new File(mContext.getFilesDir(),"crash"+File.separator);
            if(dir.exists()){
                deleteDir(dir);
            }
            if(!dir.exists()){
                dir.mkdirs();
            }

            FileOutputStream fos = null;
            try {
                fileName = dir.getAbsolutePath()
                        + File.separator
                        + getAssignTime("yyyy_MM_dd_HH:mm:ss") +".txt";
                fos = new FileOutputStream(fileName);
                fos.write(sb.toString().getBytes());
                fos.flush();
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }finally {
                if(fos != null){
                    try {
                        fos.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
        return fileName;
    }

    /**
     * 获取捕获到的异常信息
     * @param e
     * @return
     */
    private String obtainExceptionInfo(Throwable e) {
        StringWriter stringWrite = new StringWriter();
        PrintWriter printWrite = new PrintWriter(stringWrite);
        e.printStackTrace(printWrite);
        printWrite.close();
        return stringWrite.toString();
    }

    /**
     * 格式化时间
     * @param dateFormatStr
     * @return
     */
    private String getAssignTime(String dateFormatStr) {
        DateFormat dateFormat = new SimpleDateFormat(dateFormatStr);
        return dateFormat.format(System.currentTimeMillis());
    }

    /**
     * 删除文件夹
     * @param dir
     */
    private void deleteDir(File dir) {
        if(dir.isFile()){
            dir.delete();
        }else{
            File[] files = dir.listFiles();
            for(File file:files){
                deleteDir(file);
            }
            dir.delete();
        }
    }

    private HashMap<String,String> obtainSimpleInfo(Context context) {
        HashMap<String,String> map = new HashMap<>();
        PackageManager packageManager = context.getPackageManager();
        PackageInfo packageInfo = null;
        try {
            packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(),PackageManager.GET_ACTIVITIES
            );
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        map.put("versionName",packageInfo.versionName);
        map.put("versionCode",""+packageInfo.versionCode);
        map.put("MODEL","" + Build.MODEL);
        map.put("SDK_INT","" + Build.VERSION.SDK_INT);
        map.put("PRODUCT","" + Build.PRODUCT);
        map.put("MOBLE_INFO",getMobilInfo());
        return map;
    }

    /**
     *
     * @return
     */
    public static String getMobilInfo()  {
        StringBuffer sb = new StringBuffer();
        Field[] fields = Build.class.getDeclaredFields();
        try{
            for(Field field:fields){
                field.setAccessible(true);
                String name = field.getName();
                String value = field.get(null).toString();
                sb.append(name + " = " +value);
                sb.append("\n");
            }
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }
        return sb.toString();
    }
}
